﻿using System;
using System.Reflection;
using System.Data.Linq.Mapping;
using System.Collections.Generic;

namespace Suteki.Common.Extensions
{
    public static class TypeExtensions
    {
        public static PropertyInfo GetPrimaryKey(this Type entityType)
        {
            foreach (PropertyInfo property in entityType.GetProperties())
            {
                ColumnAttribute[] attributes = (ColumnAttribute[])property.GetCustomAttributes(typeof(ColumnAttribute), true);
                if (attributes.Length == 1)
                {
                    ColumnAttribute columnAttribute = attributes[0];
                    if (columnAttribute.IsPrimaryKey)
                    {
                        if (property.PropertyType != typeof(int))
                        {
                            throw new ApplicationException(string.Format("Primary key, '{0}', of type '{1}' is not int",
                                                                         property.Name, entityType));
                        }
                        return property;
                    }
                }
            }
            throw new ApplicationException(string.Format("No primary key defined for type {0}", entityType.Name));
        }

        /// <summary>
        /// Gets the property that closest matches a label property. The priority
        ///  in which the property will be obtained is the following:
        ///  
        /// 1. A property named "label"
        /// 2. A property named "name"
        /// 3. The priomary key property
        /// 
        /// The names of the properies are case agnostic.
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static PropertyInfo GetLabelProperty(this Type entityType)
        {
            PropertyInfo best_label_property = null;
            bool label_field_found = false;
            bool name_field_found = false;

            foreach (PropertyInfo property in entityType.GetProperties())
            {
                if (property.Name.ToLowerInvariant() == "label")
                {
                    best_label_property = property;
                    label_field_found = true;
                    break;
                }
                else if (property.Name.ToLowerInvariant() == "name")
                {
                    best_label_property = property;
                    name_field_found = true;
                }
            }
            if (!name_field_found && !label_field_found)
            {
                best_label_property = GetPrimaryKey(entityType);
            }
            return best_label_property;
            //throw new ApplicationException(string.Format("No name property suitable for type {0}", entityType.Name));
        }

        /// <summary>
        /// Gets the column that closest matches a label column. The priority
        ///  in which the property will be obtained is the following:
        ///  
        /// 1. A property named "label"
        /// 2. A property named "name"
        /// 3. The priomary key property
        /// 
        /// The names of the properies are case agnostic.
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public static PropertyInfo GetLabelColumn(this Type entityType)
        {
            PropertyInfo best_label_property = null;
            bool label_field_found = false;
            bool name_field_found = false;

            foreach (PropertyInfo property in entityType.GetProperties())
            {
                ColumnAttribute[] attributes = (ColumnAttribute[])property.GetCustomAttributes(typeof(ColumnAttribute), true);
                if (attributes.Length == 1)
                {
                    if (property.Name.ToLowerInvariant() == "label")
                    {
                        best_label_property = property;
                        label_field_found = true;
                        break;
                    }
                    else if (property.Name.ToLowerInvariant() == "name")
                    {
                        best_label_property = property;
                        name_field_found = true;
                    }
                }
            }
            if (!name_field_found && !label_field_found)
            {
                best_label_property = GetPrimaryKey(entityType);
            }
            return best_label_property;
            //throw new ApplicationException(string.Format("No name property suitable for type {0}", entityType.Name));
        }
        public static bool IsLinqEntity(this Type type)
        {
            TableAttribute[] attributes = (TableAttribute[])type.GetCustomAttributes(typeof(TableAttribute), true);
            if (attributes.Length == 1)
            {
                return true;
            }
            return false;
        }

        public static IEnumerable<PropertyInfo> PropertiesWithAttributeOf(this Type type, Type attributeType)
        {
            foreach (PropertyInfo property in type.GetProperties())
            {
                if (property.HasAttribute(attributeType))
                {
                    yield return property;
                }
            }
        }

        public static bool HasAttribute(this PropertyInfo property, Type attributeType)
        {
            object[] attributes = property.GetCustomAttributes(attributeType, true);
            return attributes.Length > 0;
        }
    }
}
